package com.zxl.designpattern.creator.singleton;

/**
 * @author zxl
 * @version 1.0
 * @description 设计模式-创建型模式-懒汉式单例模式（线程安全），使用锁实现
 * @date 2025/5/31 18:11
 */
public class LazyLockSingleton {

    /**
     *     volatile 关键字用于确保多个线程之间对变量的可见性。
     *     当一个线程修改了 volatile 变量的值时，其他线程能够立即看到这个修改。
     *     这对于多线程环境中的共享变量非常重要，因为它可以防止线程之间的可见性问题。
     *     例如，当一个线程修改了一个共享变量的值时，其他线程可能不会立即看到这个修改，
     *     这可能导致线程之间的不一致性。使用 volatile 关键字可以确保线程之间的可见性，
     *     从而避免这种不一致性。
     */
    private volatile static LazyLockSingleton instance;

    /**
     * 线程安全（双重检查锁）
     * 提供一个公共的静态方法，返回实例对象
     * @return
     */
    public static LazyLockSingleton getInstance(){
        if (instance == null){
            synchronized (LazyLockSingleton.class){
                if (instance == null){
                    instance = new LazyLockSingleton();
                }
            }
        }
        return instance;
    }

    /**
     * 加锁解决线程安全问题，效率低下，建议使用双重检查锁方式
     * 这种加在方法上的 synchronized，静态属性甚至不用加上 volatile 关键字
     * @return
     */
//    public static synchronized LazyLockSingleton getInstance(){
//        if (instance == null){
//            instance = new LazyLockSingleton();
//        }
//        return instance;
//    }

    private LazyLockSingleton(){
        // 防止反射破坏单例
        if (instance != null) {
            throw new RuntimeException("不允许通过反射创建单例实例");
        }
    }

    private void doSomething(){
        System.out.println("do something");
    }

    /**
     * 防止反序列化
     * 不反序列化时，Java 会先创建一个新的对象实例。
     * 若该对象所属类实现了readResolve()方法，就会调用这个方法。
     * readResolve()方法返回的对象会被直接返回给调用者，而新创建的对象实例则会被丢弃，不会被传递给调用者。
     * 因此，readResolve()方法可以确保反序列化后的对象与序列化前的对象是同一个对象。
     *
     * @return
     */
    public static LazyLockSingleton readResolve(){
        return instance;
    }
}
